<?php

namespace app\common\model;

use think\facade\Db;
use think\facade\Request;
use Yansongda\Pay\Log;
use Yansongda\Pay\Pay;

/**
 * 支付宝支付.
 */
class Alipay
{
    public $config = null;

    public static function make($agentID)
    {
        static $instance;
        if ($instance) {
            return $instance;
        }

        return $instance = new self($agentID);
    }

    public function __construct($agentId = 0,$notify_url = '')
    {
        if (empty($agentId)) {
            // 返佣，使用公司的支付账号
            $info = Db::name('config')
                ->where('type', 'alipay')
                ->column('value', 'field');

            // $info['ali_public_key'] = '../data/cert/alipay/alipayCertPublicKey_RSA2.crt';
            // $info['app_cert_public_key'] = '../data/cert/alipay/appCertPublicKey_2021002175658077.crt';
            // $info['alipay_root_cert'] = '../data/cert/alipay/alipayRootCert.crt';
            $rootPath = root_path();
            $this->config = [
                'app_id' => '2021003178601383',
                // 支付宝公钥
                'ali_public_key' =>  $rootPath.'data/cert/alipayCertPublicKey_RSA2.crt',
                'app_cert_public_key' => $rootPath.'data/cert/appCertPublicKey.crt', //应用公钥证书路径
                'alipay_root_cert' => $rootPath.'data/cert/alipayRootCert.crt', //支付宝根证书路径
                'private_key' => 'MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDOdKdb1Bh2f/1Bs7U6QjLhTQEr0qiiHuiEP8e5CyxsnukEF3/0aJ8bV03Oikz+1UgklTDW7CBZjgugDvZb1wOo2hgd6m9sTOGPrkCckPENNF0drluwf7YYGeppWEpuN0Nzx079L+vaf/AfcqL5RM3cLVF1Z8VT35iicZGYV/ZWy/bma9g2P1akcBz7uq57fCi+eyE1PTMhX8RJlewK0+W5qUlkw4eP2nc0UzblSy+FF2gX5rq+QrMakwwlk2FuCIz/NhTpomQZXuYKhpkVjV8hyfOKHEq/jy4y/7482gnP2/H++CEGsHSWpblmSozFIMcTuacvc/LFuhuC6A2EyJ7bAgMBAAECggEAU4WL4zF1yBLVUQwzp+L6FH2DmMf7YsLgTAhFc03a5gKPwBEFucnNfFEgcAsxRPLh4bLddEVIfRJjD5id/9+HYnsAwLGD7CtaITdcejqE2lOxy/0qqMex0iRB2eZXDimbRy59fR4y601QxlgpKHC2W3mV98pIYTsW07jgLuJ/DPNy2ooOleJGa0RxBE5UtRsnxB8OQOatCYaDxgLPfh6oiSq0W1PW3YqTNqnQlRfTUwK8+REw6ycewcdm++H+2wkKy0XCFQ91N6WljPqEl4X2rP+qzx7xwBT4X6PUo9Ty9z4GKkFsLX84K7D7JpbukedrZ/YrSYaQ1ux7K6QtO2To6QKBgQDrMQmNLGThcr6w/j2swfX8RiqoBH+zECJF/jxMBjp0AXjnZnXftQLX+l1vX5eYMOH2AsyCg+uOgPHeS6My1PHX8BTZ2DWzj4/Wa58Q20RvUPveIBlNF8jZfNW0TNVvdMm8VIFR9Qa2/vthHHOdHM1djklRyIpX+eMlHr9xlTB4nQKBgQDguMOozhOdwwpvN7Vd2E7AZsChNCst5VmZF+O5jsyS/B+u4YSapGs4cJdnHJElOtVJB02Mlf3KYPgBQkIJEPRub0j11EejYuXdoJ9ZyJ0EJCE/4bSUIO0/lruuimCEVss1MKcLVKPw1fZOrPG9GigB0ORfaH9ZuN932lcfHyCv1wKBgQCZg1uBqz15rmTrsDdfgQbnkIEdRDp6DYjheM2wrcwPljptiAJeb48YnFHKdXHEo/uJkVAdzK+/R0kYWPSAJGBrG0jw3GBJAObZBUxBO23S3uBXn0oEeQbfds0ir5gM9QUMiXgTn8SvQ4WfYGvSXE9rxojy+dvbCr+JpiU9pSyLPQKBgHq98IC/Lo+4/HYK45FCmKEWfpiOOhdzciDgn422pZ6S/2sx2o/sxnOpa8jyHYVMQTsGNiFXu6tSk6N8YT06eYfoWN2M+SQQ3KTVGrSbkse0RET0LwHJikx1NEX9ZwJhtdRzoonZzUG6XDJU3CUBqGB1jIdgOE71X3nDVFq3Uc85AoGABcCklIIk3A2EOYSX4G2H5HPt7KQVBblWdTcBSbBxRTFgc9MCZbGnJtukXuT/5HXyfnwfjXncgr8Bbj9mQ7Bn85Wr0NNt3adb9WBeMTz6HPHWb3jchh3PZoAsZWpJf8Hbqantj0RpfRkrN7eMLR37CL0we9Rn+mM0Utu7+ri5Qi0=',

                'notify_url' => Request::domain().'/index.php/api/notify/alipayNotify/agentId/'.$agentId,
                // 'mode' => 'dev', // optional,设置此参数，将进入沙箱模式

                'log' => [ // optional
                    'file' => $rootPath.'runtime/alipay/alipay.log',
                    'level' => 'info', // 建议生产环境等级调整为 info，开发环境为 debug
                    'type' => 'dailay', // optional, 可选 daily.
                    'max_file' => 30, // optional, 当 type 为 daily 时有效，默认 30 天
                ],
                'http' => [ // optional
                    'timeout' => 5.0,
                    'connect_timeout' => 5.0,
                    // 更多配置项请参考 [Guzzle](https://guzzle-cn.readthedocs.io/zh_CN/latest/request-options.html)
                ],
            ];



        } else {
            // 预充，使用客户的支付账号
            $info = Db::name('agent_config')
                ->where('agent_id', $agentId)
                ->find();
            $rootPath = root_path();
            $this->config = [
                'app_id' => $info['ali_app_id'],
                // 支付宝公钥
                'ali_public_key' => $info['ali_public_key'],
                // 应用密钥
                'private_key' => $info['ali_private_key'],

                'notify_url' => Request::domain().'/index.php/api/notify/alipayNotify/agentId/'.$agentId,
                // 'mode' => 'dev', // optional,设置此参数，将进入沙箱模式

                'log' => [ // optional
                    'file' => $rootPath.'runtime/alipay/alipay.log',
                    'level' => 'info', // 建议生产环境等级调整为 info，开发环境为 debug
                    'type' => 'dailay', // optional, 可选 daily.
                    'max_file' => 30, // optional, 当 type 为 daily 时有效，默认 30 天
                ],
                'http' => [ // optional
                    'timeout' => 5.0,
                    'connect_timeout' => 5.0,
                    // 更多配置项请参考 [Guzzle](https://guzzle-cn.readthedocs.io/zh_CN/latest/request-options.html)
                ],
            ];
        }

        if ($notify_url){
            $this->config['notify_url'] = $notify_url;
        }
    }

    /**
     * 扫码支付.
     *
     * @params  $order_id   订单号
     * @params  $amount     充值金额。单位：元
     * @params  $name       充值标题：充值xxxx元
     */
    public function scan($data)
    {
        $order = [
            'out_trade_no' => $data['order_id'],
            'total_amount' => fen2yuan($data['amount']),
            'subject' => $data['name'],
        ];

        try {
            $alipay = Pay::alipay($this->config)->scan($order);
        } catch (\Exception $e) {
            return fail($e->getMessage());
        }

        return success('操作成功', [
            'out_trade_no' => $data['order_id'],
            'qrcode' => $alipay->qr_code,
        ]);
    }

    /**
     * 电脑支付.
     */
    public function web($data)
    {
        $order = [
            'out_trade_no' => $data['order_id'],
            'total_amount' => fen2yuan($data['amount']),
            'subject' => $data['name'],
        ];

        try {
            $alipay = Pay::alipay($this->config)->web($order);
        } catch (\Exception $e) {
            return fail($e->getMessage());
        }

        return success('操作成功', $alipay);
    }

    /**
     * 退款.
     */
    public function refund($params)
    {
        $result = Pay::alipay($this->config)->refund([
            'out_trade_no' => $params['out_trade_no'],
            'refund_amount' => $params['refund_amount'],
            'refund_reason' => $params['refund_reason'],
        ]);

        return $result;
    }

    /**
     * 手机网站支付.
     */
    public function wap($data)
    {
        try {
            $order = [
                'out_trade_no' => $data['out_trade_no'],
                'total_amount' => fen2yuan($data['total_amount']),
                'subject' => $data['name'],
            ];
            if (empty($data['return_url'])) {
                $this->config['return_url'] = Request::domain().'/index.php/api/notify/returnUrl?channel='.$data['channel'];
            } else {
                $this->config['return_url'] = $data['return_url'];
            }
//            header('Access-Control-Allow-Origin: *');

            return Pay::alipay($this->config)->wap($order)->send();
        } catch (\Exception $e) {
            \think\facade\Log::error($e->getMessage());
//            return fail('支付宝支付配置有误，请确认');
             return fail($e->getMessage());
        }
    }

    /**
     * 支付回调.
     */
    public function notify()
    {
        $alipay = Pay::alipay($this->config);

        Db::startTrans();
        try {
            $data = $alipay->verify(); // 是的，验签就这么简单！

            Log::error('收到支付宝异步回调', $data->all());

            // 请自行对 trade_status 进行判断及其它逻辑进行判断，在支付宝的业务通知中，只有交易通知状态为 TRADE_SUCCESS 或 TRADE_FINISHED 时，支付宝才会认定为买家付款成功。
            // 1、商户需要验证该通知数据中的out_trade_no是否为商户系统中创建的订单号；
            // 2、判断total_amount是否确实为该订单的实际金额（即商户订单创建时的金额）；
            // 3、校验通知中的seller_id（或者seller_email) 是否为out_trade_no这笔单据的对应的操作方（有的时候，一个商户可能有多个seller_id/seller_email）；
            // 4、验证app_id是否为该商户本身。
            // 5、其它业务逻辑情况
            if (!in_array($data->trade_status, ['TRADE_SUCCESS', 'TRADE_FINISHED'])) {
                Log::error('支付宝异步回调-处理失败-trade_status状态异常', $data->all());

                return fail('支付宝异步回调-处理失败-trade_status状态异常');
            }
            $payLog = Db::name('pay_log')
                ->where('order_id', $data->out_trade_no)
                ->find();
            if (empty($payLog)) {
                Log::error('支付宝异步回调-处理失败-未找到对应的支付记录', $data->all());

                return fail('支付宝异步回调-处理失败-未找到对应的支付记录');
            }
            // if ($payLog['sale_price'] != yuan2fen($data->total_amount)) {
            //     Log::error('支付宝异步回调-处理失败-订单金额不符合', $data->all());
            //     return fail('支付宝异步回调-处理失败-订单金额不符合');
            // }

            if ($this->config['app_id'] != $data->app_id) {
                Log::error('支付宝异步回调-处理失败-app_id不符合', $data->all());

                return fail('支付宝异步回调-处理失败-app_id不符合');
            }

            if (2 == $payLog['status']) {
                return $alipay->success()->send();
            }

            $payLogUpdate = [
                'status' => 2,
                'trade_no' => $data->trade_no,
                'real_pay_price' => yuan2fen($data->total_amount),
            ];
            $orderUpdate = [
                'status' => 2,
                // todo 分配话费供应商
                // 'mobile_supplier_id' => 2,
            ];

            switch ($payLog['type']) {
                case 1: // 话费充值
                    $model = new \app\api\model\Mobile();
                    $model->handleSuccess($payLog, $payLogUpdate, $orderUpdate);
                    break;
                case 2: // 代理商充值
                    $model = new \app\agent\model\Recharge();
                    $payLog['trade_no'] = $data->trade_no;
                    $model->handleSuccess($payLog);
                    break;
                default:
                    return fail('类型有误.');
                    break;
            }

            Log::error('支付宝异步回调-处理成功', $data->all());

            Db::commit();
        } catch (\Exception $e) {
            Db::rollback();

            Log::error('支付宝异步回调，发生异常:2', [$e->getMessage()]);

            return fail($e->getMessage());
        }

        return $alipay->success()->send(); // laravel 框架中请直接 `return $alipay->success()`
    }

    /**
     * 订单查询.
     */
    public function find($outTradeNo)
    {
        $order = [
            'out_trade_no' => $outTradeNo,
        ];

        try {
            $alipay = Pay::alipay($this->config)->find($order);

            return $alipay->toArray();
        } catch (\Exception $e) {
            return false;
        }
    }

    /**
     * 根据支付宝交易号查询交易
     * Array.
            [msg] => Success
            [buyer_logon_id] => 183******51
            [buyer_pay_amount] => 0.00
            [buyer_user_id] => 2088902866363733
            [invoice_amount] => 0.00
            [out_trade_no] => 16306842848902866363733
            [point_amount] => 0.00
            [receipt_amount] => 0.00
            [send_pay_date] => 2021-09-03 23:51:29
            [total_amount] => 0.01
            [trade_no] => 2021090322001463731436278722
            [trade_status] => TRADE_SUCCESS
        )
     */
    public function findByTradeNo($tradeNo)
    {
        $order = [
            'trade_no' => $tradeNo,
        ];

        try {
            $alipay = Pay::alipay($this->config)->find($order);
        } catch (\Exception $e) {
            return false;
        }

        return $alipay->toArray();
    }

    /**
     * 订单是否已经支付.
     *
     * 未支付返回 false，已支付返回 trade_no
     */
    public function checkPaid($outTradeNo)
    {
        $pay = self::find($outTradeNo);
        if (false === $pay || !in_array($pay['trade_status'], ['TRADE_SUCCESS', 'TRADE_FINISHED'])) {
            return false;
        }

        return [
            'trade_no' => $pay['trade_no'],
        ];
    }

    /*
     转账
    */
//    public function transfer($data)
//    {
//        //halt($this->config);
//        return Pay::alipay($this->config)->transfer($data);
//    }
}
